package com.base.network

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import android.support.annotation.RequiresApi
import java.lang.ref.WeakReference

/**
 * @author zhouzechao
 * @Description 网络辅助类
 */
class Neter(context: Context) {
    private val mAppContext: Context = context.applicationContext
    private val mListeners = LinkedHashSet<WeakReference<INetCallback>>()
    private var mState = NetState.NOTINIT

    private val mConnectivityManager: ConnectivityManager
    private var networkStateCallback: NetStateCallback? = null
    private var networkStateBroadcastReceiver: NetStateBroadcastReceiver? = null

    companion object {
        private var instance: Neter? = null

        /**
         * 初始化
         */
        fun init(context: Context) {
            if (instance == null) {
                synchronized(Neter::class.java) {
                    if (instance == null) {
                        instance = Neter(context.applicationContext)
                    }
                }
            }
        }

        /**
         * 获取状态 {link com.base.network.NetState}
         */
        fun getState(): NetState? {
            return instance?.mState ?: instance?.run { getState() } ?: NetState.NOTINIT
        }

        /**
         * 添加回调
         */
        fun addListener(iNetCallback: INetCallback) {
            instance?.addListener(iNetCallback)
        }

        /**
         * 去掉回调
         */
        fun removeListener(iNetCallback: INetCallback) {
            instance?.removeListener(iNetCallback)
        }
    }

    /**
     * 获取状态
     */
    private fun getState(): NetState {
        val networkInfo = mConnectivityManager.activeNetworkInfo
        if (networkInfo != null && networkInfo.isConnected) {
            when {
                networkInfo.type == ConnectivityManager.TYPE_WIFI -> return NetState.WIFI
                networkInfo.type == ConnectivityManager.TYPE_MOBILE -> return NetState.MOBILE
                networkInfo.type == ConnectivityManager.TYPE_ETHERNET -> return NetState.LINE
                else -> NetState.CONNECT
            }
        }
        return NetState.NONE
    }

    /**
     * 初始化
     */
    init {
        mConnectivityManager = mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (isNetworkCallbackSupported()) {
            networkStateCallback = NetStateCallback()
        } else {
            networkStateBroadcastReceiver = NetStateBroadcastReceiver()
        }
    }

    /**
     * 去除监听，当空的时候 调用 @method unRegister 解除注册
     */
    private fun removeListener(iNetCallback: INetCallback) {
        synchronized(Neter::class.java) {
            for (weak in mListeners) {
                val mNetCall = weak.get()
                if (mNetCall != null) {
                    if (mNetCall == iNetCallback) {
                        mListeners.remove(weak)
                    }
                } else {
                    mListeners.remove(weak)
                }
            }
            if (mListeners.isEmpty()) {
                unRegister()
            }
        }
    }

    /**
     * 添加监听，当不为空 调用 @method register注册
     */
    private fun addListener(iNetCallback: INetCallback) {
        synchronized(Neter::class.java) {
            mListeners.add(WeakReference(iNetCallback)).takeIf { mListeners.size == 1 }?.apply {
                register()
            }
        }
    }

    private fun register() {
        if (isNetworkCallbackSupported()) {
            mConnectivityManager.registerDefaultNetworkCallback(networkStateCallback)
        } else {
            mAppContext.registerReceiver(networkStateBroadcastReceiver,
                IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
        }
    }

    private fun unRegister() {
        if (isNetworkCallbackSupported()) {
            mConnectivityManager.unregisterNetworkCallback(networkStateCallback)
        } else {
            mAppContext.unregisterReceiver(networkStateBroadcastReceiver)
        }
    }

    private fun isNetworkCallbackSupported(): Boolean {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private inner class NetStateCallback : ConnectivityManager.NetworkCallback() {
        override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
            val wifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
            val mobile = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
            val line = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
            val hasNet = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            mState = NetState.NONE
            if (hasNet) {
                when {
                    wifi -> mState = NetState.WIFI
                    mobile -> mState = NetState.MOBILE
                    line -> mState = NetState.LINE
                }
                mState = NetState.CONNECT
            }
            for (netCallback in mListeners) {
                netCallback.get()?.onNetChange(mState)
            }
        }

        override fun onLost(network: Network) {
            var capabilities = mConnectivityManager.getNetworkCapabilities(network)
            val wifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
            val mobile = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
            val line = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
            val hasNet = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            mState = NetState.NONE
            if (hasNet) {
                when {
                    wifi -> mState = NetState.WIFI
                    mobile -> mState = NetState.MOBILE
                    line -> mState = NetState.LINE
                }
                mState = NetState.CONNECT
            }
            for (netCallback in mListeners) {
                netCallback.get()?.onNetChange(mState)
            }
        }
    }

    private inner class NetStateBroadcastReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val action = intent?.action
            if (action == ConnectivityManager.CONNECTIVITY_ACTION) {
                mState = NetState.NONE
                val networkInfo = mConnectivityManager.activeNetworkInfo
                if (networkInfo != null && networkInfo.isConnected) {
                    when {
                        networkInfo.getType() == ConnectivityManager.TYPE_WIFI -> mState = NetState.WIFI
                        networkInfo.getType() == ConnectivityManager.TYPE_MOBILE -> mState = NetState.MOBILE
                        networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET -> mState = NetState.LINE
                    }
                    mState = NetState.CONNECT
                }
                for (netCallback in mListeners) {
                    netCallback.get()?.onNetChange(mState)
                }
            }
        }
    }
}